#!/usr/bin/env node

const fs = require('fs-extra');
const path = require('path');
const iconv = require('iconv-lite');
const child_process = require('child_process');
const JSZIP = require('jszip');

function copyToClipboard(file) {
    let command;
    switch(process.platform) {
        case "darwin":
        command = `cat "${file}"|pbcopy`;
        break;
        case "win32":
        const cf = path.join(__dirname, 'cat_file_to_clipboard');
        if (!fs.existsSync(cf)) {
            fs.writeFileSync(cf, '#!/bin/bash\ncat $1 > /dev/clipboard');
        }
        command = `bash "${cf}" "${file}"`;
        break;
        default:
        command = `cat "${file}" > /dev/clipboard`;
    }
    child_process.exec(command, function(err, stdout, stderr) {
        fs.unlinkSync(file);
    });
}
function getClipboardData() {
    return new Promise(resolve=>{
        let command;
        switch(process.platform) {
            case "darwin":
            command = `pbpaste`;
            break;
            default:
            command = `cat /dev/clipboard`;
        }
        child_process.exec(command, { maxBuffer: 1024*1024*50 }, function(err, stdout, stderr) {
            resolve(stdout);
        });
    });
}
function zipFile(zip, dir) {
    if (fs.statSync(dir).isDirectory()) {
        const files = fs.readdirSync(dir);
        for (const file of files) {
            const fullPath = path.join(dir, file);
            if (fs.statSync(fullPath).isDirectory()) {
                zipFile(zip, fullPath);
            } else {
                zip.file(fullPath, fs.readFileSync(fullPath));
            }
        }
    } else {
        zip.file(path.basename(dir), fs.readFileSync(dir));
    }
}
function copyFile(file) {
    if (!fs.existsSync(file)) {
        return console.log(`${file} 不存在`);
    }
    const tempFile = '.__tempfile';
    const zip = new JSZIP();
    zipFile(zip, file);
    zip.generateAsync({
        type: "base64",
        encodeFileName: function (string) {
            return iconv.encode(string, 'utf-8');
        }
    }).then(base64=>{
        fs.writeFileSync(tempFile, 'xclip|');
        fs.appendFileSync(tempFile, base64);
        copyToClipboard(tempFile);
        console.log('done');
    });
}
async function pasteFile(file = '.') {
    if (fs.existsSync(file) && !fs.statSync(file).isDirectory()) {
        return console.log(`${file} 必须是文件夹`);
    }
    fs.ensureDirSync(file);
    const data = await getClipboardData();
    const list = data.split('|');
    if (!(list.length === 2 && list[0] === 'xclip')) {
        return console.log(`请先在目标机上执行 xcopy 文件|文件夹`);
    }
    new JSZIP().folder(file).loadAsync(list[1], { base64: true, createFolders: true }).then(function (zip) {
        zip.forEach(function (relativePath, zipEntry) {
            if (!zipEntry.dir) {
                const name = zipEntry.name.replace(/\\/g, '/');
                if (fs.existsSync(name)) {
                    throw '文件已经存在';
                }
                fs.ensureFileSync(name);
                zipEntry.async('nodebuffer').then(content => fs.writeFileSync(name, content));
            }
        });
    });
}
function main(command, file) {
    if (command !== '-c' && command !== '-p') {
        console.log('');
        console.log('Usage:');
        console.log('   在一台机器上执行:');
        console.log('   xclip -c 文件|文件夹');
        console.log('');
        console.log('   在另外一台机器上执行:');
        return console.log('   xclip -p [目标文件夹]');
    }
    if (command === '-c') {
        copyFile(file);
    } else {
        pasteFile(file);
    }
}

main(...process.argv.slice(2));
